package cn.com.headfree.util;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class SimpleThreadPool extends ThreadPoolExecutor {
	private Logger log = LogManager.getLogger(getClass());

	private AtomicInteger taskBalance = new AtomicInteger(0);

	private int queueCapacity = 100;

	private static SimpleThreadPool threadPool = null;

	public SimpleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
	}

	public SimpleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveSecond,
			BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveSecond, TimeUnit.SECONDS, workQueue);
	}

	public SimpleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveSecond) {
		super(corePoolSize, maximumPoolSize, keepAliveSecond, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
	}

	public SimpleThreadPool(BlockingQueue<Runnable> workQueue) {
		super(1, 1, 1L, TimeUnit.SECONDS, workQueue);
	}

	public SimpleThreadPool() {
		super(1, 1, 1L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
	}

	public static SimpleThreadPool createSingleThread() {
		if (threadPool != null) {
			return threadPool;
		} else {
			threadPool = new SimpleThreadPool(6, 6, 60L);
			return threadPool;
		}
	}

	protected void afterExecute(Runnable r, Throwable t) {
		super.afterExecute(r, t);
		this.taskBalance.decrementAndGet();
		// printException(r, t);
		if (this.log.isDebugEnabled()) {
			this.log.debug("task : " + r.getClass().getSimpleName() + " completed,Throwable:" + t + ",taskBalance:"
					+ getTaskBalance());
		}
		synchronized (this) {
			notifyAll();
		}
	}

	private void printException(Runnable r, Throwable t) {
		if (t == null && r instanceof Future<?>) {
			try {
				Future<?> future = (Future<?>) r;
				if (future.isDone())
					future.get();
			} catch (CancellationException ce) {
				t = ce;
			} catch (ExecutionException ee) {
				t = ee.getCause();
			} catch (InterruptedException ie) {
				Thread.currentThread().interrupt(); // ignore/reset
			}
		}
		if (t != null)
			this.log.error(t.getMessage(), t);
	}

	public void execute(Runnable task) {
		this.taskBalance.getAndIncrement();
		super.execute(task);
	}

	public boolean addTask(Runnable task) {
		if (this.queueCapacity < getQueue().size()) {
			this.log.warn("task Queue full!");
			return false;
		}
		execute(task);

		return true;
	}

	public int getTaskBalance() {
		return this.taskBalance.get();
	}

	public void setQueueCapacity(int capacity) {
		this.queueCapacity = capacity;
	}

	public void setMaxPoolSize(int size) {
		super.setMaximumPoolSize(size);
	}

	public void setKeepAliveSecond(int time) {
		super.setKeepAliveTime(time, TimeUnit.SECONDS);
	}

	public void waitCompleted() {
		try {
			synchronized (this) {
				while (getTaskBalance() > 0)
					wait(500L);
			}
		} catch (InterruptedException localInterruptedException) {
			this.log.info("taskBalance: " + getTaskBalance());
		}
	}
}
